﻿//#define GPS_EMULATOR

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Controls.Maps;
using Microsoft.Phone.Shell;
using System.Device.Location;
//using GpsEmulatorClient;



namespace OptymalizatorTrasy
{
    public partial class MainPage : PhoneApplicationPage
    {

        public MapLayer layerP = (App.Current as App).layerP; //stworzenie warst pinesek i tras oraz przypisanie do nich analogicznych zmiennych globalnych
        public MapLayer layerT = (App.Current as App).layerT;
       // private Geokodowanie geoKoder; //utworzenie elementu do geokodowanie
        private SzybkaTrasa szybkaTrasaK; //utworzenie elementu do zamiany dźwięku na tekst i odwrotnie, a także narywania i odtwarzania
        private IGeoPositionWatcher<GeoCoordinate> watcher = null; //geolokalizator


        //zmienne pomocnicze
        private bool czyNagrywam = false;
        private bool czyEdycja = false;
        private bool isDragging = false;
        private bool czyDodawanie = false;
        public bool czySzybka = (App.Current as App).czySzybka;
        private int ilePinesekOK = 1;
        private int ileTrasOK = 0;

        //pomocnicze pineski
        public Pushpin pinPozycja = null; //pineska określająca naszą pozycję
        public Pushpin poprzednia = null; //pineska, która była poprzednio zaznaczona
        public Pushpin doDodania; //pineska, która ma zostać dodana

        //pomcnicze trasy
        private MapPolyline poprzedniaTrasa = null; //trasa, która była zaznaczona poprzednio

        // Constructor
        public MainPage()
        {
            InitializeComponent();
            startGeo(); //rozpoczęcie śledzenia pozycji
            szybkaTrasaK = new SzybkaTrasa(this); //inicjacja elementu szybka trasa

            if (czySzybka) trybSzybkiej.Visibility = Visibility.Visible;
            dlugoscTrasy.Text = (App.Current as App).dystans;
        }

        //wykonanie odpowiednich czynności w zależności od tego z której strony przechodzimy do naszej mapy
        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
              
            if (this.NavigationContext.QueryString.ContainsKey("status")) //jeśli przechodzimy ze strony z dodawaniem pinesek
            {
                if (NavigationContext.QueryString["status"].CompareTo("doDodania") == 0) //jeśli pineska ma zostać dopiero dodana (dodawanie z Mapy)
                {
                    ApplicationBar.IsVisible = false;
                    GuzikiDodawania.Visibility = System.Windows.Visibility.Visible;
                    NazwaDodawania.Visibility = System.Windows.Visibility.Visible;
                    czyDodawanie = true;
                    nazwaD.Text = NavigationContext.QueryString["nazwa"];

                    //dodanie nowej pineski do mapy i przypisanie jej EventHandlerow
                    doDodania = new Pushpin();
                    doDodania.Location = (App.Current as App).srodek;
                    doDodania.Content = nazwaD.Text;
                    doDodania.Background = new SolidColorBrush(Colors.Red);
                    doDodania.MouseLeftButtonDown += new MouseButtonEventHandler(pushpin_MouseLeftButtonDown);
                    doDodania.MouseLeftButtonUp += new MouseButtonEventHandler(pushpin_MouseLeftButtonUp);
                    doDodania.MouseMove += new MouseEventHandler(pushpin_MouseMove);

                    layerP.Children.Add(doDodania);
                }
                mapa.ZoomLevel = (App.Current as App).zoom;
                mapa.Center = (App.Current as App).srodek;

            }
            else if(mapa.Children.Count == 0)//spełnione tylko gdy ma miejsce pierwsze uruchomienie aplikacji
            {
                //USUNAC POTEM!!!!
                //Pushpin pinPozycja1 = new Pushpin();
                //pinPozycja1.Location = new GeoCoordinate(54, 18);
               // layerP.Children.Add(pinPozycja1);
                //DOTĄD

                //(App.Current as App).srodek = pinPozycja1.Location; //ustawienie środka mapy na naszą pozycję 
                //(App.Current as App).zoom = 9; //ustawienie domyślnego zoomu
            }

       //     mapa.Center = (App.Current as App).srodek; //ustawienie środka mapy tam gdzie byl wczesniej
       //     mapa.ZoomLevel = (App.Current as App).zoom; //ustawienie przyblizenia na takie jakie bylo wczesniej
            mapa.Children.Add(layerP); //dodanie do mapy warstwy pinesek
            mapa.Children.Add(layerT); //dodanie do mapy warstwy tras         
            mapa.MapPan += new EventHandler<MapDragEventArgs>(mapaDragging); //dodajemy EventHandler, że gdy ruszamy pineską, to mapa jest nieruchoma
        }

        #region przyciski_menu

        private void pozycja_Click(object sender, EventArgs e)
        {
           mapa.Center = pinPozycja.Location;
        }

        private void miasto_Click(object sender, EventArgs e)
        {
            ApplicationBarIconButton b = sender as ApplicationBarIconButton;

            if (!czyEdycja) //jeśli nie jesteśmy w trybie edycji to Szybka Trasa
            {
                if (!czyNagrywam)
                {
                    b.IconUri = (new Uri(@"/icons/appbar.microC.rest.png", UriKind.Relative));
                    szybkaTrasaK.nagrywaj();
                }
                else
                {
                    b.IconUri = (new Uri(@"/icons/appbar.micro.rest.png", UriKind.Relative));
                    szybkaTrasaK.zakoncz();
                }
                czyNagrywam = !czyNagrywam;
            }
            else if (poprzednia != null || poprzedniaTrasa!=null) //jeśli jesteśmy w trybie edycji to usuwanie pineski
            {
                if (poprzednia != null)
                {
                    layerP.Children.Remove(poprzednia);
                    poprzednia = null;
                }
                else
                {
                    layerT.Children.Remove(poprzedniaTrasa);
                    poprzedniaTrasa = null;
                }
            }

          
            
        }

        private void edytuj_Click(object sender, EventArgs e)
        {
            dodajHandlery(ilePinesekOK); //dodanie Handlerów pineskom
            dodajHandleryTras(ileTrasOK); //dodanie Handlerów trasom

            //przypisanie zmiennym odpowiednich guzików
            ApplicationBarIconButton b = sender as ApplicationBarIconButton;
            ApplicationBarIconButton b2 = (ApplicationBarIconButton)ApplicationBar.Buttons[1];

            //zamiana ikonek przycisków
            if (czyEdycja) //wychodzimy z trybu edycji
            {
                if (poprzednia != null) poprzednia.Background = new SolidColorBrush(Colors.Black);
                if (poprzedniaTrasa != null) poprzedniaTrasa.Background = new SolidColorBrush(Colors.Blue);
                b.IconUri = (new Uri(@"/icons/appbar.edit.rest.png", UriKind.Relative));
                b2.IconUri = (new Uri(@"/icons/appbar.micro.rest.png", UriKind.Relative));
            }
            else //wchodzimy do trybu edycji
            {
                b.IconUri = (new Uri(@"/icons/appbar.editC.rest.png", UriKind.Relative));
                b2.IconUri = (new Uri(@"/icons/appbar.delete.rest.png", UriKind.Relative));
            }

            czyEdycja = !czyEdycja;
        }

        private void dodaj_Click(object sender, EventArgs e)
        {
            (App.Current as App).srodek = mapa.Center; //aktualizacja centrum mapy
            (App.Current as App).zoom = mapa.ZoomLevel; //aktualizacja przyblizenia mapy
            (App.Current as App).czySzybka = czySzybka;
            (App.Current as App).dystans = dlugoscTrasy.Text;
            mapa.Children.Remove(layerP); //usuniecie warstwy Pinesek - niezbedne, by potem dokonac jej aktualizacji
            mapa.Children.Remove(layerT); //usuniecie warstwy Tras - niezbedne, by potem dokonac jej aktualizacji
            layerP.Children.RemoveAt(0);
            NavigationService.Navigate(new Uri("/Dodawanie.xaml", UriKind.Relative)); //nawigacja do strony dodawania
        }

        #endregion

        #region przyciski_listy

        private void liczTrase_Click(object sender, EventArgs e)
        {
            //rysowanie trasy, o ile są co najmniej dwa punkty na mapie
            if (layerP.Children.Count > 1)
            {
                //wywołanie algorytmu komiwojażera na punktach znajdujących się na mapie
                Komiwojazer komiwojazer = new Komiwojazer(layerP, layerT);
                komiwojazer.algorytm();
                //wyświetlenie trasy
                komiwojazer.Trasa(dlugoscTrasy);
            }

        }

        private void szybkaTrasa_Click(object sender, EventArgs e)
        {

            if (czySzybka)
            {
                trybSzybkiej.Visibility = Visibility.Collapsed;
            }
            else
            {
                trybSzybkiej.Visibility = Visibility.Visible;
            }

            czySzybka = !czySzybka;
        }

        private void czyscTrasy_Click(object sender, EventArgs e)
        {
            layerT.Children.Clear();
            ileTrasOK = 0;
            dlugoscTrasy.Text = "Brak wprowadzonej trasy";
        }

        private void czyscWszystko_Click(object sender, EventArgs e)
        {
            layerT.Children.Clear();
            
            //USUNAC POTEM!!!!
            Pushpin pinPozycja1 = (Pushpin) layerP.Children.ElementAt(0);

            layerP.Children.Clear();

            //pinPozycja1.Location = new GeoCoordinate(54, 18);
            layerP.Children.Add(pinPozycja1);
            //DOTĄD
            (App.Current as App).indexPinesek = 1;
            ileTrasOK = 0;
            ilePinesekOK = 1;

            dlugoscTrasy.Text = "Brak wprowadzonej trasy";
        }

        #endregion

        #region przyciski_dodawania
        //anulowanie dodawania aktualnej pineski
        private void anulujD_Click(object sender, RoutedEventArgs e)
        {
            layerP.Children.Remove(doDodania);
            ApplicationBar.IsVisible = true;
            GuzikiDodawania.Visibility = System.Windows.Visibility.Collapsed;
            NazwaDodawania.Visibility = System.Windows.Visibility.Collapsed;
            czyDodawanie = false;
        }
        //dodawanie pineski
        private void dodajD_Click(object sender, RoutedEventArgs e)
        {
            doDodania.Background = new SolidColorBrush(Colors.Black);
            ApplicationBar.IsVisible = true;
            GuzikiDodawania.Visibility = System.Windows.Visibility.Collapsed;
            NazwaDodawania.Visibility = System.Windows.Visibility.Collapsed;
            czyDodawanie = false;
            (App.Current as App).indexPinesek++;
        }
        //dodanie pineski i dodawanie kolejnej
        private void nextD_Click(object sender, RoutedEventArgs e)
        {
            
            (App.Current as App).indexPinesek++;     

            //dodanie nowej pineski do mapy i przypisanie jej EventHandlerow
            doDodania.Background = new SolidColorBrush(Colors.Black);
            doDodania.Content = nazwaD.Text;

            nazwaD.Text = "pineska" + Convert.ToString((App.Current as App).indexPinesek);
            doDodania = new Pushpin();
            doDodania.Location = mapa.Center;
            doDodania.Content = nazwaD.Text;
            doDodania.Background = new SolidColorBrush(Colors.Red);

            layerP.Children.Add(doDodania);

            doDodania.MouseLeftButtonDown += new MouseButtonEventHandler(pushpin_MouseLeftButtonDown);
            doDodania.MouseLeftButtonUp += new MouseButtonEventHandler(pushpin_MouseLeftButtonUp);
            doDodania.MouseMove += new MouseEventHandler(pushpin_MouseMove);
        }

        #endregion

        #region geolokalizacja

        void startGeo()
        {
            if (watcher == null)
            {
                    #if GPS_EMULATOR
                          watcher = new GpsEmulatorClient.GeoCoordinateWatcher();
                    #else
                                watcher = new System.Device.Location.GeoCoordinateWatcher(GeoPositionAccuracy.High)
                                {
                                        MovementThreshold = 10
                                };
                    #endif

                watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);
                watcher.Start();
                
                if (pinPozycja == null)
                {
                    pinPozycja = new Pushpin();
                    pinPozycja.Style = this.Resources["PushpinStyle"] as Style;
                    pinPozycja.Location = watcher.Position.Location;
                    layerP.Children.Add(pinPozycja);
                    mapa.Center = pinPozycja.Location;
                    mapa.ZoomLevel = 9;
                }
            }
        }


        void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => MyPositionChanged(e));
            
        }

        void MyPositionChanged(GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            pinPozycja.Location = e.Position.Location;
           // mapa.Center = pinPozycja.Location;
           // LatitudeTextBlock.Text = e.Position.Location.Latitude.ToString("0.000");
            //LongitudeTextBlock.Text = e.Position.Location.Longitude.ToString("0.000");
        }
        #endregion

        #region EdycjaPinesek
        //dodanie Pineskom EventHandlerow
        private void dodajHandlery(int start)
        {
            while (start < layerP.Children.Count())
            {
                Pushpin p = (Pushpin) layerP.Children.ElementAt(start);
                p.MouseLeftButtonDown += new MouseButtonEventHandler(pushpin_MouseLeftButtonDown);  //dodanie trzech eventhandlerów do każdej nowoutworzonej pineski
                p.MouseLeftButtonUp += new MouseButtonEventHandler(pushpin_MouseLeftButtonUp);
                p.MouseMove += new MouseEventHandler(pushpin_MouseMove);
                start++;
                ilePinesekOK++;
            }

        }

        //eventHandler dla  mapy -> gdy ruszamy pineską, to mapa jest nieruchoma
        private void mapaDragging(object sender, MapDragEventArgs e)
        {
            if (isDragging)
            {
                e.Handled = true;
            }
        }

        //EventHandler obsługujący naciśnięcie na pineską
        private void pushpin_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Pushpin pin = sender as Pushpin;

            if (czyEdycja)  //jeśli jesteśmy w trybie edycji
            {
                //jeśli istnieje poprzednia pineska, to musimy ją odznaczyć
                if (poprzednia != null) poprzednia.Background = new SolidColorBrush(Colors.Black);
                //jeśli istenieje poprzednia trasa to musimy ją odznaczyć i usunąć
                if (poprzedniaTrasa != null)
                {
                    poprzedniaTrasa.Background = new SolidColorBrush(Colors.Blue);
                    poprzedniaTrasa = null;
                }

                pin.Background = new SolidColorBrush(Colors.Red); //zaznaczamy aktualnie edytowaną pineske na kolor czerwony
                pin.CaptureMouse();
                isDragging = true;
                poprzednia = pin; //ustawiamy poprzednią pineskę na aktualną
            }
            else if (czyDodawanie && pin == doDodania) //jeśli jesteśmy w trybie dodawania, a kliknięta pineska, to jest ta, która jest właśnie dodawana
            {
                pin.CaptureMouse();
                isDragging = true;
            }
        }

        //EventHandler obsługujący zwolnienie pineski
        private void pushpin_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            Pushpin pin = sender as Pushpin;

            if (czyEdycja) //jeśli jesteśmy w trybie edycji
            {
                pin.ReleaseMouseCapture();
                isDragging = false;
            }
            else if (czyDodawanie && pin == doDodania) //jeśli jesteśmy w trybie dodawania, a kliknięta pineska, to jest ta, która jest właśnie dodawana
            {
                pin.ReleaseMouseCapture();
                isDragging = false;
            }
        }

        //EventHandler obsługujący ruch myszką z pineską
        private void pushpin_MouseMove(object sender, MouseEventArgs e)
        {
            Pushpin pin = sender as Pushpin;

            //jeśli jesteśmy w trybie Edycji, albo Dodajemy pineskę
            if (czyEdycja || (czyDodawanie && pin == doDodania))
            {
                pin.Location = mapa.ViewportPointToLocation(e.GetPosition(mapa));
            }
        }

        #endregion

        #region EdycjaTras
        //dodanie Pineskom EventHandlerow
        private void dodajHandleryTras(int start)
        {
            while (start < layerT.Children.Count())
            {
                MapPolyline p = (MapPolyline)layerT.Children.ElementAt(start);
                p.MouseLeftButtonDown += new MouseButtonEventHandler(trasa_MouseLeftButtonDown);  //dodanie eventHandlera naciśnięcia na trasę
                start++;
                ileTrasOK++;
            }

        }

        //EventHandler obsługujący naciśnięcie na trasę
        private void trasa_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            MapPolyline mapPoly = sender as MapPolyline;

            if (czyEdycja)  //jeśli jesteśmy w trybie edycji
            {
                //jeśli istnieje poprzednia zaznaczona trasa, to musimy ją odznaczyć
                if (poprzedniaTrasa != null) poprzedniaTrasa.Background = new SolidColorBrush(Colors.Blue);
                //jeśli istenieje poprzednia zaznaczona pineska to musimy ją odznaczyć i ustawić na null
                if (poprzednia != null)
                {
                    poprzednia.Background = new SolidColorBrush(Colors.Black);
                    poprzednia = null; 
                }

                mapPoly.Background = new SolidColorBrush(Colors.Red); //zaznaczamy aktualnie edytowaną trasę na kolor czerwony
                poprzedniaTrasa = mapPoly; //ustawiamy poprzednią trasę na aktualną
                
            }
        }

        #endregion

        private void zoomIn_Click(object sender, RoutedEventArgs e)
        {
            mapa.ZoomLevel++;
        }

        private void zoomOut_Click(object sender, RoutedEventArgs e)
        {
            mapa.ZoomLevel--;
        }
    }
}